import {  MiddlewareCreater, Route, ServerAPI, createAuthHelper } from 'f2e-server3';
import { DBKey, PermissionKey, ServiceAll, ServiceOptions, User, UserRole } from './interface';
import creatorFileService from './service/file';
import { clientPages, md5 } from './utils';
import * as initData from './init/data'

export const createMiddleRBAC = (service?: ServiceAll, options: ServiceOptions = {}): MiddlewareCreater => {
    if (!service) {
        service = creatorFileService({});
    }
    const {
        prefix = '/admin',
        logout_url,
        load_page = true,
    } = options
    return {
        mode: ['dev', 'prod'],
        name: 'rbac',
        execute(conf) {
            const route = new Route(conf);
            const authHelper = createAuthHelper({});
            const { userService, userRoleService, userPermissionService } = service;
            const getLoginUser: ServerAPI<never, User | null> = async function (_, ctx) {
                const loginUser = authHelper.getLoginUser(ctx);
                if (!loginUser?.user) return null;
                const user = await userService.getUserByUsername(loginUser.user.username);
                const rolesInfo: UserRole[] = []
                if (!user) return null;
                if (!user.roles || user.roles.length === 0) {
                    return { ...user, roles: [], permissions: new Set(), }
                } else {
                    const permissions = new Set<DBKey>();
                    for (let i = 0; i < user.roles.length; i++) {
                        const role = await userRoleService.getUserRoleByKey(user.roles[i]);
                        if (!role) throw new Error('角色不存在');
                        rolesInfo.push(role);
                        for (let j = 0; j < role.permissions?.length || 0; j++) {
                            permissions.add(role.permissions[j])
                        }
                    }
                    return { ...user, permissions, rolesInfo, }
                }
            }
            const actions: Record<string, [PermissionKey, ServerAPI<any, any>]> = {
                'permission.list': [PermissionKey.RBAC_PERMISSION, userPermissionService.permissionList],
                'permission.create': [PermissionKey.RBAC_PERMISSION, userPermissionService.permissionCreate],
                'permission.update': [PermissionKey.RBAC_PERMISSION, userPermissionService.permissionUpdate],
                'permission.delete': [PermissionKey.RBAC_PERMISSION, userPermissionService.permissionDelete],
                'role.list': [PermissionKey.RBAC_ROLE, userRoleService.roleList],
                'role.create': [PermissionKey.RBAC_ROLE, userRoleService.roleCreate],
                'role.update': [PermissionKey.RBAC_ROLE, userRoleService.roleUpdate],
                'role.delete': [PermissionKey.RBAC_ROLE, userRoleService.roleDelete],
                'user.create': [PermissionKey.RBAC_USER, userService.userCreate],
                'user.update': [PermissionKey.RBAC_USER, userService.userUpdate],
                'user.delete': [PermissionKey.RBAC_USER, userService.userDelete],
                'user.list': [PermissionKey.RBAC_USER, userService.userList],

                'user.updatePassword': [PermissionKey.RBAC_SELF, async (body: Record<'password' | 'newPassword', string>, ctx) => {
                    const loginUser = authHelper.getLoginUser(ctx);
                    if (loginUser?.user) {
                        if (body.newPassword) {
                            await userService.userUpdate({
                                username: loginUser?.user.username,
                                password: md5(body.newPassword),
                            });
                            return {
                                success: true,
                            }
                        } else {
                            return {
                                success: false,
                                msg: '请输入新密码',
                            }
                        }
                    } else {
                        return {
                            success: false,
                            msg: '未登录',
                        }
                    }
                }],
            }

            for (const [key, [permissionKey, fetchAPI]] of Object.entries(actions)) {
                route.on(`${prefix}/loginUser`, async (body, ctx) => {
                    const loginUser = await getLoginUser(body, ctx);
                    if (!loginUser) return {
                        success: false,
                        msg: '未登录',
                    }
                    return {
                        success: true,
                        data: {
                            ...loginUser,
                            permissions: Array.from(loginUser.permissions ?? []),
                        },
                    }
                })
                route.on(`${prefix}/${key}`, async (body, ctx) => {
                    const loginUser = await getLoginUser(body, ctx);
                    if (!loginUser) return {
                        success: false,
                        msg: '未登录',
                    }
                    if (!loginUser.permissions?.has(permissionKey)) {
                        return {
                            success: false,
                            msg: '无权限',
                        }
                    }
                    return fetchAPI(body, ctx);
                }, { method: 'POST' });
            }

            if (load_page) {
                const pages = clientPages(prefix);
                route.on(prefix, () => pages.index, { type: 'raw', sourceType: 'html' })
                route.on(`${prefix}/client.js`, () => `;LOGOUT_URL="${logout_url}";` + pages['client.js'], { type: 'raw', sourceType: 'html' })
                route.on(`${prefix}/client.js.map`, () => pages['client.js.map'], { type: 'raw', sourceType: 'html' })
            }

            return {
                onMemoryInit: () => {
                    // 初始化数据
                    return service.init(initData);
                },
                onRoute: route.execute,
            }
        }
    }
}

export { createService as createServiceFile } from './service/file';
export { createService as createServiceMongo } from './service/mongo';
